//
//  Lattice.h
//  phi_four
//
//  Created by Snir Gazit on 3/8/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef Lattice_h
#define Lattice_h

#include "../HelpLibs/ArrayMultiD.h"
#include "../HelpLibs/def.h"

using namespace std;
using namespace boost;

typedef boost::array<int, DIM> IndexType;

enum MoveDir {
	LEFT = 0, RIGHT = 1
};

enum CreateRemove {
	CREATE = 0, REMOVE = 1
};

struct Bond {
	int dir;
	boost::array<int, 2> bondVal;
	friend class serialization::access;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & bondVal;
		ar & dir;
	}
};
typedef Bond BondType;

struct Site {
	typedef ArrayMulti<Site, DIM> SiteArray;
	typedef SiteArray::iterator SiteArrayIterator;
	typedef SiteArray::IterIndex SiteArrayIndexIterator;
	struct BondData {
		BondType * bond_;
		SiteArrayIterator neighbourSite_;
		MoveDir moveDir_;
		CreateRemove createRemove_;
		BondData(BondType *bond, SiteArrayIterator neighboursSite,
				MoveDir moveDir, CreateRemove createRemove) :
				bond_(bond), neighbourSite_(neighboursSite), moveDir_(moveDir), createRemove_(
						createRemove) {
		}
		BondData(BondData const &bondData) :
				bond_(bondData.bond_), neighbourSite_(bondData.neighbourSite_), moveDir_(
						bondData.moveDir_), createRemove_(
						bondData.createRemove_) {
		}
	};
	typedef vector<BondData> BondArray;
	BondArray bondArray_;
	IndexType siteIndex_;
	int totalBonds_;
	friend class serialization::access;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & totalBonds_;
	}
};

class Lattice {
public:
	// Typedefs
	typedef Site::BondData BondData;
	typedef vector<BondData> BondDataVector;
	typedef vector<BondData>::iterator BondDataVectorIterator;
	typedef boost::array<int, DIM> IndexType;
	typedef Site::SiteArrayIterator SiteIter;
	typedef Site::SiteArrayIndexIterator SiteIterIndex;
	typedef ArrayMulti<vector<BondType>, DIM> BondArray;
	typedef BondArray::iterator BondArrayIter;
	// functions
	void init(boost::array<int, DIM> const &latSize);
	void initSquare(boost::array<int, DIM> const &latSize);
	SiteIter getIra();
	SiteIter getMasha();
	void setIra(Lattice::SiteIter &iter);
	void setMasha(Lattice::SiteIter &iter);
	SiteIter getSite(int distanceFromStart);
	boost::array<int, DIM> getSizes();
	bool isClosed() const;
	void moveIraMasha(IndexType moveToPos);
	int getCordinationNumber() const;
	int getNumOfSites() const;
	// Debug Functions
	bool testConfiguration(int &totalBonds);
	// Measure Functions
	BondArrayIter BondBegin();
	BondArrayIter BondEnd();
	SiteIter siteBegin();
	SiteIter siteEnd();
	int getTotalBonds() const;
	void setToalBonds(int totalBonds);
	void setNormRatio(double normRatio);
	double getNormRatio() const;
	void dump(string fileName);
	void read(string fileName);
	template<class Archive>
	void save(Archive & ar, const unsigned int version) const;
	template<class Archive>
	void load(Archive & ar, const unsigned int version);BOOST_SERIALIZATION_SPLIT_MEMBER()private:
	Site::SiteArray siteLattice_;
	BondArray bondLattice_;
	SiteIter ira_, masha_;
	boost::array<int, DIM> latSize_;
	int cordinationNumber_;
	double normRatio_;
	int totalBonds_;
};
template<class Archive>
void Lattice::save(Archive & ar, const unsigned int version) const {
	for (auto itb = bondLattice_.begin(); itb != bondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira = ira_ - siteLattice_.begin();
	ar & ira;
	int masha = masha_ - siteLattice_.begin();
	ar & masha;
	ar & totalBonds_;
}
template<class Archive>
void Lattice::load(Archive & ar, const unsigned int version) {
	for (auto itb = bondLattice_.begin(); itb != bondLattice_.end(); itb++)
		for (auto itd = itb->begin(); itd != itb->end(); itd++)
			ar & *itd;
	for (auto itb = siteLattice_.begin(); itb != siteLattice_.end(); itb++)
		ar & *itb;
	int ira;
	ar & ira;
	ira_ = this->siteBegin() + ira;
	int masha;
	ar & masha;
	masha_ = this->siteBegin() + masha;
	ar & totalBonds_;
}
#endif
